package com.spsy.order.controller;

import java.sql.*;
import java.math.BigDecimal;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

public class OrderMultiThreadInsert {
    // 数据库配置（替换为实际环境）
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/ry_2303a_cloud?useSSL=false&rewriteBatchedStatements=true";
    private static final String USER = "root";
    private static final String PASSWORD = "root";
    
    // 插入配置
    private static final int TOTAL_ROWS = 5000000; // 总数据量
    private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors() * 2; // 线程数（基于CPU核心）
    private static final int BATCH_SIZE = 1000; // 每批次提交数量（根据数据库性能调整）
    
    // 全局自增序列号（确保order_no唯一）
    private static final AtomicLong GLOBAL_SEQ = new AtomicLong(0);

    public static void main(String[] args) throws Exception {
        long startTime = System.currentTimeMillis();
        
        // 创建线程池（带缓冲和拒绝策略）
        ExecutorService executor = new ThreadPoolExecutor(
                THREAD_COUNT,
                THREAD_COUNT,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy() // 任务满时由提交者执行，避免丢失
        );
        
        // 计算每个线程的插入量（最后一个线程处理余数）
        int baseRows = TOTAL_ROWS / THREAD_COUNT;
        int remainRows = TOTAL_ROWS % THREAD_COUNT;
        
        // 提交任务并等待完成
        CompletionService<Void> completionService = new ExecutorCompletionService<>(executor);
        for (int i = 0; i < THREAD_COUNT; i++) {
            int rows = (i == THREAD_COUNT - 1) ? baseRows + remainRows : baseRows;
            completionService.submit(() -> insertBatch(rows));
        }
        
        // 等待所有线程完成
        for (int i = 0; i < THREAD_COUNT; i++) {
            completionService.take().get();
        }
        
        // 关闭资源
        executor.shutdown();
        long endTime = System.currentTimeMillis();
        
        System.out.printf("500万条数据插入完成！耗时：%d秒，线程数：%d，每批次：%d条%n",
                (endTime - startTime) / 1000, THREAD_COUNT, BATCH_SIZE);
    }

    /**
     * 单线程批量插入数据
     * @param rows 本线程需插入的总条数
     */
    private static Void insertBatch(int rows) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            // 获取数据库连接（生产环境建议用HikariCP连接池）
            conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
            conn.setAutoCommit(false); // 关闭自动提交，开启事务
            
            // 插入SQL（适配所有字段，id自增无需插入）
            String sql = "INSERT INTO `order` (" +
                    "order_no, order_no2, user_id, total_amount, discount_amount, " +
                    "shipping_fee, pay_amount, payment_method, payment_time, order_status, " +
                    "consignee, phone, address, remark, is_deleted, create_time, update_time" +
                    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
            pstmt = conn.prepareStatement(sql);
            
            int count = 0;
            while (count < rows) {
                // 生成唯一订单号（32位：前缀+时间戳+全局序列号）
                long seq = GLOBAL_SEQ.incrementAndGet();
                String orderNo = String.format("ORD%s%010d", System.currentTimeMillis(), seq);
                orderNo = orderNo.substring(0, Math.min(orderNo.length(), 32)); // 限制32位
                
                // 生成order_no2（255位，可包含额外信息）
                String orderNo2 = "BACKUP_" + orderNo + "_" + Thread.currentThread().getId() + "_" + count;
                
                // 生成用户ID（100万以内随机用户）
                long userId = ThreadLocalRandom.current().nextLong(1, 1000000);
                
                // 生成金额（总金额10-10000元，折扣0-总金额的30%）
                BigDecimal totalAmount = new BigDecimal(ThreadLocalRandom.current().nextDouble(10, 10000))
                        .setScale(2, BigDecimal.ROUND_HALF_UP);
                BigDecimal discountAmount = totalAmount.multiply(new BigDecimal(ThreadLocalRandom.current().nextDouble(0, 0.3)))
                        .setScale(2, BigDecimal.ROUND_HALF_UP);
                BigDecimal shippingFee = new BigDecimal(ThreadLocalRandom.current().nextDouble(0, 20))
                        .setScale(2, BigDecimal.ROUND_HALF_UP);
                BigDecimal payAmount = totalAmount.subtract(discountAmount).add(shippingFee)
                        .setScale(2, BigDecimal.ROUND_HALF_UP);
                
                // 支付方式（1-支付宝，2-微信，3-银行卡）
                int paymentMethod = ThreadLocalRandom.current().nextInt(1, 4);
                
                // 订单状态（0-未支付，1-已支付，2-已发货，3-已完成，4-已取消）
                int orderStatus = ThreadLocalRandom.current().nextInt(0, 5);
                
                // 收货信息（随机生成合理格式）
                String consignee = "收货人" + ThreadLocalRandom.current().nextInt(10000, 99999);
                String phone = "13" + ThreadLocalRandom.current().nextLong(100000000, 999999999);
                String address = "省份" + (count % 34 + 1) + "市" + (count % 100 + 1) + "区街道" + count;
                String remark = count % 10 == 0 ? "加急订单" : (count % 20 == 0 ? "开发测试数据" : "");
                
                // 是否删除（0-未删除，1-已删除，默认99%未删除）
                int isDeleted = ThreadLocalRandom.current().nextInt(100) < 99 ? 0 : 1;
                
                // 设置参数（按SQL字段顺序）
                pstmt.setString(1, orderNo);
                pstmt.setString(2, orderNo2);
                pstmt.setLong(3, userId);
                pstmt.setBigDecimal(4, totalAmount);
                pstmt.setBigDecimal(5, discountAmount);
                pstmt.setBigDecimal(6, shippingFee);
                pstmt.setBigDecimal(7, payAmount);
                pstmt.setInt(8, paymentMethod);
                pstmt.setObject(9, orderStatus == 1 ? new Timestamp(System.currentTimeMillis()) : null); // 仅已支付有支付时间
                pstmt.setInt(10, orderStatus);
                pstmt.setString(11, consignee);
                pstmt.setString(12, phone);
                pstmt.setString(13, address);
                pstmt.setString(14, remark);
                pstmt.setInt(15, isDeleted);
                
                // 添加到批处理
                pstmt.addBatch();
                count++;
                
                // 达到批次大小则提交
                if (count % BATCH_SIZE == 0) {
                    pstmt.executeBatch();
                    conn.commit();
                    pstmt.clearBatch(); // 清空缓存
                }
            }
            
            // 提交剩余数据
            if (count % BATCH_SIZE != 0) {
                pstmt.executeBatch();
                conn.commit();
            }
            
            System.out.printf("线程[%s]完成插入，共%d条数据%n",
                    Thread.currentThread().getName(), rows);
            
        } catch (SQLException e) {
            if (conn != null) {
                try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); }
            }
            throw new RuntimeException("插入失败：" + e.getMessage(), e);
        } finally {
            // 关闭资源
            if (pstmt != null) try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); }
            if (conn != null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
        }
        return null;
    }
}